using FlexiCommerce.Components;

namespace FlexiCommerce.Collections
{
	/// <summary>
	/// Builds a hierarchy of nodes between a certain item and one of it's 
	/// ancestors (or the root item). This is useful in certain situations when
	/// creating a navigation menu.
	/// </summary>
    public class BranchHierarchyBuilder : HierarchyBuilder
    {
        private readonly HierarchicalPersistenceItem initialItem;
        private readonly HierarchicalPersistenceItem lastAncestor;
        bool appendAdditionalLevel = false;

        /// <summary>
        /// Initializes a new instance of the <see cref="BranchHierarchyBuilder"/> class.
        /// </summary>
        /// <param name="initialItem">The initial item.</param>
        /// <param name="lastAncestor">The last ancestor.</param>
        /// <param name="appendAdditionalLevel">if set to <c>true</c> [append additional level].</param>
        public BranchHierarchyBuilder(HierarchicalPersistenceItem initialItem, HierarchicalPersistenceItem lastAncestor, bool appendAdditionalLevel)
        {
            this.initialItem = initialItem;
            this.lastAncestor = lastAncestor;
            this.appendAdditionalLevel = appendAdditionalLevel;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BranchHierarchyBuilder"/> class.
        /// </summary>
        /// <param name="initialItem">The initial item.</param>
        /// <param name="lastAncestor">The last ancestor.</param>
        public BranchHierarchyBuilder(HierarchicalPersistenceItem initialItem, HierarchicalPersistenceItem lastAncestor)
        {
            this.initialItem = initialItem;
            this.lastAncestor = lastAncestor;
        }

        /// <summary>
        /// Builds this instance.
        /// </summary>
        /// <returns></returns>
        public override HierarchyNode<HierarchicalPersistenceItem> Build()
        {
            if (initialItem == lastAncestor && !appendAdditionalLevel)
            {
                return new HierarchyNode<HierarchicalPersistenceItem>(initialItem);
            }

            HierarchyNode<HierarchicalPersistenceItem> previousNode = null;
            foreach (HierarchicalPersistenceItem currentItem in Find.EnumerateParents(initialItem, lastAncestor, appendAdditionalLevel))
            {
                HierarchyNode<HierarchicalPersistenceItem> currentNode = new HierarchyNode<HierarchicalPersistenceItem>(currentItem);
                if (previousNode != null)
                {
                    previousNode.Parent = currentNode;
                }

                foreach (HierarchicalPersistenceItem childItem in GetChildren(currentItem))
                {
                    if (previousNode != null && previousNode.Current == childItem)
                    {
                        currentNode.Children.Add(previousNode);
                    }
                    else
                    {
                        HierarchyNode<HierarchicalPersistenceItem> childNode = new HierarchyNode<HierarchicalPersistenceItem>(childItem);
                        currentNode.Children.Add(childNode);
                        childNode.Parent = currentNode;
                    }
                }
                previousNode = currentNode;
            }
            return previousNode;
        }
    }
}